import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:learning_content_admin_pannel/root/domain/use_cases/backup_learning_content_to_file/use_case.dart';
import 'package:learning_content_admin_pannel/root/domain/use_cases/handle_settings_page_opening_request/use_case.dart';
import 'package:learning_content_admin_pannel/root/domain/use_cases/restore_learning_content_from_file/use_case.dart';
import 'package:learning_content_admin_pannel/root/domain/use_cases/sign_out/use_case.dart';
import 'package:learning_content_admin_pannel.core/auth/application/bloc/bloc.dart';
import 'package:learning_content_admin_pannel.core/core/domain/entities/user.dart';
import 'package:learning_content_admin_pannel.core/core/domain/utils/either_extension.dart';
import 'package:learning_content_admin_pannel.core/learning_content/application/bloc/bloc.dart';
import 'package:learning_content_admin_pannel.core/root_navigator/application/bloc/bloc.dart';

part 'bloc_state.dart';

class RootWidgetBloc extends Cubit<RootWidgetBlocState> {
  RootWidgetBloc({
    required AuthBloc authBloc,
    required LearningContentBloc learningContentBloc,
    required RootNavigatorBloc rootNavigatorBloc,
    required BackupLearningContentToFile backupLearningContentToFile,
    required HandleSettingsPageOpeningRequest handleSettingsPageOpeningRequest,
    required RestoreLearningContentFromFile restoreLearningContentFromFile,
    required SignOut signOut,
  })  : _authBloc = authBloc,
        _learningContentBloc = learningContentBloc,
        _rootNavigatorBloc = rootNavigatorBloc,
        _backupLearningContentToFile = backupLearningContentToFile,
        _handleSettingsPageOpeningRequest = handleSettingsPageOpeningRequest,
        _restoreLearningContentFromFile = restoreLearningContentFromFile,
        _signOut = signOut,
        super(_getInitialState(
          authBlocState: authBloc.state,
        )) {
    _authBlocSubscription = authBloc.stream.listen(_onAuthBlocStateChanged);
  }

  final AuthBloc _authBloc;
  final LearningContentBloc _learningContentBloc;
  final RootNavigatorBloc _rootNavigatorBloc;

  final BackupLearningContentToFile _backupLearningContentToFile;
  final HandleSettingsPageOpeningRequest _handleSettingsPageOpeningRequest;
  final RestoreLearningContentFromFile _restoreLearningContentFromFile;
  final SignOut _signOut;

  late final StreamSubscription<AuthBlocState> _authBlocSubscription;

  static RootWidgetBlocState _getInitialState({
    required AuthBlocState? authBlocState,
  }) {
    return RootWidgetBlocState(
      user: authBlocState?.user,
    );
  }

  void _onAuthBlocStateChanged(AuthBlocState authBlocState) {
    emit(state.copyWith(
      user: () => authBlocState.user,
    ));
  }

  void requestSigningOut() {
    if (state.user == null) {
      return;
    }

    final result = _signOut(
      refreshToken: _authBloc.state!.accessCredentials!.refreshToken,
    );

    emit(state.copyWith(
      user: () => result.user,
    ));

    _authBloc.setAuthenticationData(
      user: () => result.user,
      accessCredentials: () => result.accessCredentials,
    );
  }

  void requestLearningContentBackupToFile() {
    _backupLearningContentToFile(
      lexicalItemMap: _learningContentBloc.state!.lexicalItemMap,
      collectionListItems: _learningContentBloc.state!.collectionListItems,
    );
  }

  void requestLearningContentRestorationFromFile() async {
    final failureOrResult = await _restoreLearningContentFromFile();

    if (failureOrResult.isLeft()) {
      final failure = failureOrResult.asLeft();

      switch (failure) {
        case InvalidFormatLearningContentRestorationFromFileFailure():
          return;
      }
    }

    final result = failureOrResult.asRight();

    if (result == null) {
      return;
    }

    _learningContentBloc.updateWith(
      collectionListItems: () => result.collectionListItems,
      lexicalItemMap: () => result.lexicalItemMap,
    );
  }

  void requestSettingsPageOpening() {
    final result = _handleSettingsPageOpeningRequest(
      rootNavigatorPageModels: _rootNavigatorBloc.state.pageModels,
      rootNavigatorPageModelToTransitionInfo: _rootNavigatorBloc.state.pageModelToTransitionInfo,
    );

    _rootNavigatorBloc.requestPageStackUpdate(
      pageModels: result.rootNavigatorPageModels,
      pageModelToTransitionInfo: result.rootNavigatorPageModelToTransitionInfo,
    );
  }

  @override
  Future<void> close() {
    _authBlocSubscription.cancel();
    return super.close();
  }
}
